home *** CD-ROM | disk | FTP | other *** search
- /*
- Uniflex Kermit's support task.
-
- This privileged task accounts for the following functions:
-
- 1. Set the baudrate of any terminal with that possibility.
- 2. Get the number of free blocks from the current device.
- 3. Set the specified date on a specified file.
- 4. Set the default directory (to keep track with the caller).
- 5. Send a break to the specified device.
-
- This program reads stdin (normally a pipe) to get the function.
- Current functions are:
-
- 1. 'b' - set the baudrate on the specified device
- 2. 'd' - set the specified date on the specified file
- 3. 'f' - get number of free blocks on the specified device
- 4. 's' - set the default directory
- 5. 'w' - send 'break' to the specified device
- 6. 'e' - exit the support task
-
- */
-
- #asm
- info UniFLEX Kermit's support task
- info Author: Jur van der Burg
- info Nettelhorst 56
- info 2402 LS Alphen aan den Rijn
- info The Netherlands
- info Version: V 1.2
- #endasm
-
- #define PROTOCOL_VERSION 2
-
- #include <stdio.h>
- #include <stat.h>
- #include <modes.h>
- #include <signal.h>
- #include <sys/dir.h>
- #include <setjmp.h>
-
- #define chtim touch /* other name in my library */
-
- #define TRUE 1
- #define FALSE 0
- #define IN 0
- #define OUT 1
- #define BAUD 0
- #define BREAK 1
- #define ERROR (-1)
-
- #define TIMBYTE 0x2b
-
- main()
- {
- char command,
- mask,
- errmsg[128],
- device[30],
- file[128];
- int status,
- len,
- owner,
- perms;
- unsigned int baudrate;
- struct stat buf;
- long get_freedisk(),
- free_blks,
- date;
-
- fstat(0,&buf); /* check standard input */
- if (buf.st_nlink != 0) /* input must come from a pipe */
- exit(0); /* bye bye, leave him in confusion */
-
- signal(SIGTERM,SIG_IGN); /* Ignore this signals */
- signal(SIGHUP,SIG_IGN);
- signal(SIGQUIT,SIG_IGN);
- signal(SIGINT,SIG_IGN);
- command = PROTOCOL_VERSION;
- write(OUT,&command,1); /* Send acknowledge to parent */
- while (TRUE) /* Keep looking for commands */
- {
- if (read(IN,&command,1) <= 0) /* Get command byte */
- exit(1); /* Read error */
- switch(command)
- {
- case 'b': /* Set device baudrate */
- read(IN,&len,2); /* Get device name length */
- read(IN,device,len); /* Get device name */
- read(IN,&baudrate,2); /* Get the baudrate */
- read(IN,&mask,1); /* Get the mask */
- status = set_dev(device,baudrate,mask,errmsg,BAUD); /* Set */
- write(OUT,&status,2); /* Return status */
- if (status)
- send_error(errmsg); /* Send error message */
- break;
-
- case 'w': /* Send break to device */
- read(IN,&len,2); /* Get device name length */
- read(IN,device,len); /* Get device name */
- status = set_dev(device,0,0,errmsg,BREAK); /* Send it */
- write(OUT,&status,2); /* Return status */
- if (status)
- send_error(errmsg); /* Send error message */
- break;
-
- case 'd':
- read(IN,&len,2); /* Get file name length */
- read(IN,file,len); /* Get file name */
- read(IN,&date,4); /* Get the date */
- status = set_date(file,date,errmsg); /* Set it */
- write(OUT,&status,2); /* Return status */
- if (status)
- send_error(errmsg); /* Send error message */
- break;
-
- case 'f':
- read(IN,&len,2); /* Get device name length */
- read(IN,device,len); /* Get device name */
- free_blks = get_freedisk(device,errmsg);/* Get # of blocks */
- write(OUT,&free_blks,4); /* Send to parent */
- if (free_blks == (long) ERROR)
- send_error(errmsg); /* Send error message */
- break;
-
- case 's':
- read(IN,&len,2); /* Get directory name length */
- read(IN,device,len); /* Get directory name */
- status = set_dir(device,errmsg); /* Set it */
- write(OUT,&status,2); /* Return status */
- if (status)
- send_error(errmsg); /* Send error message */
- break;
-
- case 'e':
- exit(0); /* bye bye */
-
- default:
- break; /* Ignore unknown command */
- }
- }
- }
-
- send_error(msg)
- char *msg;
- {
- int length;
-
- length = strlen(msg) + 1; /* Must send terminator as well */
- write(OUT,&length,2); /* Send length */
- write(OUT,msg,length); /* Send message */
- }
-
- /*
- Routine to set the baudrate of a port, or to send a break to it.
-
- The user must either be the owner or have read and write
- access to the selected device. A check will be made if the
- system consists of new hardware. In the case of old hardware
- the baudrate is not under program control.
- */
-
- #define P_TTY 0x5c /* Pointer to tty structure */
- #define P_NTTY 0x5008 /* Pointer to number of tty's */
-
- int valid_speed[] = { /* Table containing valid speed's */
- 75,0xff,
- 150,0xee,
- 300,0xdd,
- 600,0xcc,
- 1200,0xbb,
- 2400,0xaa,
- 4800,0x99,
- 9600,0x88,
- 0
- };
-
- struct ttydef { /* Internal UniFLEX tty structure definition */
- char *rawq,
- *canq,
- *outq;
- unsigned int devadr;
- char flags,
- delay,
- major,
- minor,
- delcnt,
- col,
- kill,
- erase,
- speed,
- type,
- state,
- xstate };
-
- #define ISOPEN 0x04 /* Current state */
-
- jmp_buf env;
-
- set_dev(dev,speed,mask,errmsg,what)
- char *dev;
- unsigned int speed;
- char *errmsg;
- char mask,
- what;
- {
- int *fp,
- *fp1,
- *p,
- i,
- timeout();
- char found,
- speed_val,
- n_tty;
- unsigned int c,
- np;
- struct stat buf;
- struct ttydef tt_dsc;
- struct ttydef *sp;
-
- if (stat(dev,&buf)) /* Get device parameters */
- return(prterr("Invalid device specified",errmsg));
-
- if ((buf.st_mode & S_IFMT) != S_IFCHR) /* Check for a character device */
- return(prterr("Not a character device",errmsg));
- buf.st_mode &= S_IPRM; /* Mask type bits */
- if (!((buf.st_mode & S_IOREAD) && /* Check for read and write */
- (buf.st_mode & S_IOWRITE))) /* access for others */
- if (buf.st_uid != getuid()) /* No access, check if he owns */
- /* the device */
- return(prterr("Don't own device",errmsg));
-
- if (what == BAUD)
- {
- found = FALSE;
- p = valid_speed;
- while (*p)
- {
- if (speed == *p++) /* Compare against table */
- {
- speed_val = *p; /* Got it ! */
- found = TRUE;
- break;
- }
- p++; /* Point to next entry */
- }
- if (!found)
- return(prterr("Invalid speed specified",errmsg));
- if (mask)
- speed_val &= 0x77; /* Mask RTS and DCD */
- }
-
- /*
- The following piece of code ensures that a device address will
- be available in the internal data structures for the specified
- device. This is simply done by opening the device. In case it's
- not ready (modem for example) a timeout has been setup to allow
- the program to continue.
- */
-
- signal(SIGALRM,timeout); /* Catch the timeout trap */
- alarm(1); /* One second timeout */
- if (!setjmp(env)) /* If for the first time */
- fp = open(dev,2); /* Open the port */
- alarm(0); /* Reset timer */
- close(fp);
-
- if ((fp = open("/dev/smem",2)) == ERROR) /* Must open this one */
- return(prterr("Error opening '/dev/smem'",errmsg));
- readat(fp,P_NTTY,&np,2); /* Get pointer to number of tty's */
- readat(fp,np,&n_tty,1); /* Get number of tty's */
- readat(fp,P_TTY,&sp,2); /* Get pointer to TTY structure */
- found = FALSE;
- for (i = 0; i < n_tty; i++)
- {
- readat(fp,sp++,&tt_dsc,sizeof(struct ttydef));/* Read total structure */
- if (tt_dsc.devadr == 0) /* Skip on zero device address */
- continue;
-
- if ((tt_dsc.major == ((int)(buf.st_size >> 16) & 0xff)) &&
- (tt_dsc.minor == ((int)buf.st_size & 0xff))) /* Chk maj + min id */
- {
- readat(fp,tt_dsc.devadr + 2,&c,2); /* Get speed register */
- if ((c == 0xffff) || (what == BREAK)) /* Should read as 'ffff' */
- found = TRUE;
- else
- return(prterr("Baudrate not programmable",errmsg));
- break;
- }
- }
- if (found)
- {
- setuid(0); /* Make sure we've got the priv's */
- if (what == BAUD)
- writeat(fp,tt_dsc.devadr + 2,&speed_val,1); /* Update speed */
- else if (what == BREAK)
- poke_tty(fp,&tt_dsc,--sp);
- }
- else
- return(prterr("Unable to set baudrate",errmsg));
- close(fp);
- return(NULL);
- }
-
- poke_tty(fp,tt_dsc,sp)
- int *fp;
- struct ttydef *tt_dsc,
- *sp;
- {
- char break_val,
- org_value,
- new_speed;
-
- org_value = (tt_dsc->speed & ~0x1c) | 0x81; /* Current characteristics */
- if (!(tt_dsc->state & ISOPEN)) /* RTS high if port closed */
- org_value |= 0x40;
- break_val = org_value | 0x60; /* Add 'break' bits */
- new_speed = tt_dsc->speed | 0x60;
- writeat(fp,&sp->speed,&new_speed,1); /* break will not be terminated */
- writeat(fp,tt_dsc->devadr,&break_val,1); /* if new char is received */
- short_delay(fp,3); /* 300 Ms delay */
- writeat(fp,&sp->speed,&tt_dsc->speed,1);
- writeat(fp,tt_dsc->devadr,&org_value,1);
- }
-
- readat(fp,address,value,count)
- int *fp;
- unsigned int address;
- char *value;
- int count;
- {
- lseek(fp, (unsigned long)address, 0);
- read (fp, value, count);
- }
-
- writeat(fp,address,value,count)
- int *fp;
- unsigned int address;
- char *value;
- int count;
- {
- lseek(fp, (unsigned long)address, 0);
- write(fp, value, count);
- }
-
- short_delay(fp,time)
- int *fp, time;
- {
- int i;
- char n,
- m;
-
- n = m = -1;
- for (i = 0; i < time + 1; i++)
- {
- while (n == m)
- {
- lseek(fp, (long)TIMBYTE, 0); /* Position to time byute */
- read(fp,&m,1); /* Read current value */
- }
- n = m;
- }
- }
-
-
- timeout()
- {
- longjmp(env,TRUE); /* Return after timeout */
- }
-
- prterr(str,errstr)
- char *str,
- *errstr;
- {
- sprintf(errstr,"%s",str);
- return(ERROR);
- }
-
- /*
- This routine returns the number of free blocks on the specified device
- or directory. The real device is found by searching for it in the '/dev'
- directory, and comparing the major and minor id of the device with the
- device number of the specified directory. If the device name is found,
- a 'sync' is done to be sure that the information on the disk is current.
- Then the SIR is read and the number of free blocks is retrieved from that.
- */
-
- long get_freedisk(indev,errstr)
- char *indev,
- *errstr;
- {
- struct stat statbuf;
- struct direct dirptr;
- int device,
- status,
- fpt;
- unsigned int mode;
- char found,
- filename[20];
- long freeblks,
- get_disk();
-
- fpt = ERROR;
- found = FALSE; /* Loop end indicator */
- strcpy(filename,"/dev/");
- if (!stat(indev,&statbuf)) /* Get stat of specified directory */
- {
- device = statbuf.st_dev; /* Save device major and minor */
- mode = statbuf.st_mode & S_IFMT; /* mask for file type */
- if (mode == S_IFCHR) /* Character device not allowed */
- return(prterr("Invalid device or file specified",errstr));
- else if (mode == S_IFBLK) /* already a block device ? */
- {
- strcpy(filename,indev); /* supply device name */
- found = TRUE;
- }
- if ((fpt = open("/dev",0)) != ERROR)
- while (!found) /* Until we're done... */
- {
- status = read(fpt,&dirptr,sizeof(struct direct)); /* Get entry */
- if ((status == ERROR) || (status == NULL))/* Quit on err or EOF */
- break;
- if (dirptr.d_ino) /* If not deleted */
- {
- strcpy(&filename[5],dirptr.d_name);
- if (stat(filename,&statbuf)) /* Get status */
- break;
- else
- {
- statbuf.st_mode &= S_IFMT; /* Mask file type bits */
- if ((statbuf.st_mode == S_IFBLK) && /* block type device */
- (statbuf.st_size == device)) /* Maj. and Min. match ? */
- found = TRUE; /* Yes, return name */
- }
- }
- }
- }
- else
- return(prterr("Invalid device or file specified",errstr));
-
- if (fpt != ERROR)
- close(fpt); /* We're done with it */
- if (found)
- if ((freeblks = get_disk(filename)) != ERROR) /* Get the data */
- return(freeblks);
- return(prterr("Disk read error",errstr));
- }
-
- long get_disk(name)
- char *name;
- {
- int dpt;
- unsigned char freeb[3];
- long size;
-
- size = ERROR; /* assume error */
- if ((dpt = open(name,0)) == ERROR) /* Open the block device */
- return(ERROR);
- sync(); /* Make sure count is up to date */
- if (lseek(dpt,(long) 512 + 21, 0) != ERROR) /* Position in SIR */
- if (read(dpt,freeb,3) != ERROR) /* Get the three bytes */
- l3tol(&size,freeb,1); /* Convert to long int */
- close(dpt);
- return (size);
- }
-
- set_date(filename,filedate,errmsg)
- char *filename,
- *errmsg;
- long filedate;
- {
- if (chtim(filename,filedate) == ERROR) /* change the date */
- return(prterr("Error setting file date",errmsg));
- else
- return(NULL);
- }
-
- set_dir(directory,errmsg)
- char *directory,
- *errmsg;
- {
- if (chdir(directory) == ERROR)
- return(prterr("Error setting directory",errmsg));
- else
- return NULL;
- }
-